
package Application;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.geom.Dimension2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JOptionPane;

import Excepciones.BoundaryViolationException;
import Excepciones.EmptyListException;
import Excepciones.EmptyStackException;
import Excepciones.EmptyTreeException;
import Excepciones.InvalidLevelException;
import Excepciones.InvalidPositionException;
import GeneralTree.Arbol;
import GeneralTree.TNode;
import TDALista.Lista;
import TDALista.Position;
import TDALista.PositionList;
import TDAPila.Pila;

/**
 * Interfaz Grafica del programa
 * 
 * @author Martin Schiaffino [93718]
 * @author Nicolas Garcia [93078]
 * 
 */
public class NewJFrame extends javax.swing.JFrame {

	/**
	 * Constructor de la ventana
	 */
	public NewJFrame() {
		try {
			/*
			 * Carga las imagenes (los fondos primero y las demas despues de
			 * inicializar los componentes
			 */
			background = ImageIO.read(getClass().getResource(
					"/images/fondo_gris.jpg"));
			background2 = ImageIO.read(getClass().getResource(
					"/images/black.jpg"));
			initComponents();
			green = ImageIO.read(getClass().getResource(
					"/images/green_node.png"));
			flecha = ImageIO.read(getClass().getResource(
					"/images/flecha_small_blue.png"));
			blue = ImageIO
					.read(getClass().getResource("/images/blue_node.png"));
			orange = ImageIO.read(getClass().getResource(
					"/images/orange_node.png"));
			gray = ImageIO
					.read(getClass().getResource("/images/gray_node.png"));
			red = ImageIO.read(getClass().getResource("/images/red_node.png"));
			setIconImage(green);
			// Dimension de los nodos
			nodoSize = new Dimension(48, 48);
		} catch (IOException e) {
			System.out
					.println("Error de lectura. No se pueden leer las imagenes");
		}
	}

	/**
	 * This method is called from within the constructor to initialize the form.
	 * WARNING: Do NOT modify this code. The content of this method is always
	 * regenerated by the Form Editor.
	 */
	@SuppressWarnings("unchecked")
	// <editor-fold defaultstate="collapsed"
	// <editor-fold defaultstate="collapsed"
	// <editor-fold defaultstate="collapsed"
	// <editor-fold defaultstate="collapsed"
	// <editor-fold defaultstate="collapsed"
	// <editor-fold defaultstate="collapsed"
	// <editor-fold defaultstate="collapsed"
	// <editor-fold defaultstate="collapsed"
	// <editor-fold defaultstate="collapsed"
	// <editor-fold defaultstate="collapsed"
	// <editor-fold defaultstate="collapsed"
	// <editor-fold defaultstate="collapsed"
	// <editor-fold defaultstate="collapsed"
	// <editor-fold defaultstate="collapsed"
	// <editor-fold defaultstate="collapsed"
	// <editor-fold defaultstate="collapsed"
	// <editor-fold defaultstate="collapsed"
	// <editor-fold defaultstate="collapsed"
	// <editor-fold defaultstate="collapsed"
	// <editor-fold defaultstate="collapsed"
	// <editor-fold defaultstate="collapsed"
	// desc="Generated Code">//GEN-BEGIN:initComponents
	private void initComponents() {

		clickDerecho = new javax.swing.JPopupMenu();
		ctxAddSon = new javax.swing.JMenuItem();
		ctxDeleteNode = new javax.swing.JMenuItem();
		panelDeFondo = new javax.swing.JPanel() {
			public void paint(Graphics e) {
				e.drawImage(background, 0, 0, null);
				setOpaque(false);
				super.paint(e);
			}
		};
		panelOperaciones = new javax.swing.JPanel();
		btnLoadTree = new javax.swing.JButton();
		panelAdd = new javax.swing.JPanel();
		btnAddNode = new javax.swing.JButton();
		cbPadres = new javax.swing.JComboBox();
		txtRotulo = new javax.swing.JTextField();
		lblRotulo = new javax.swing.JLabel();
		lblPadre = new javax.swing.JLabel();
		panelEliminar = new javax.swing.JPanel();
		btnDeleteLevel = new javax.swing.JButton();
		cbNiveles = new javax.swing.JComboBox();
		lblNivel = new javax.swing.JLabel();
		panelAncCam = new javax.swing.JPanel();
		cbDesde = new javax.swing.JComboBox();
		cbHasta = new javax.swing.JComboBox();
		lblDesde = new javax.swing.JLabel();
		lblHasta = new javax.swing.JLabel();
		panelMostrarAC = new javax.swing.JPanel();
		chkCamino = new javax.swing.JCheckBox();
		chkAncestro = new javax.swing.JCheckBox();
		btnEliminarArbol = new javax.swing.JButton();
		panelGraficos = new javax.swing.JPanel();
		panelRecorridos = new javax.swing.JPanel();
		panelTipoRecorrido = new javax.swing.JPanel();
		radioPre = new javax.swing.JRadioButton();
		radioPos = new javax.swing.JRadioButton();
		scrollRecorrido = new javax.swing.JScrollPane();
		mpdRecorrido = new javax.swing.JPanel() {
			public void paint(Graphics e) {
				Graphics2D g = (Graphics2D) e;
				g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
						RenderingHints.VALUE_ANTIALIAS_ON);
				graficarRecorrido((Graphics2D) e);
			}
		};
		panelArbol = new javax.swing.JPanel();
		scrollArbol = new javax.swing.JScrollPane();
		mpdArbol = new javax.swing.JPanel() {
			public void paint(Graphics e) {
				// super.paintComponent(e);
				Graphics2D g = (Graphics2D) e;
				g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
						RenderingHints.VALUE_ANTIALIAS_ON);
				if (radioNiveles.isSelected()) {
					if (mpdArbol.getPreferredSize().getHeight() < niveles * 56 + 20) {
						mpdArbol.setPreferredSize(new Dimension(mpdArbol
								.getPreferredSize().width, niveles * 56 + 20));
						mpdArbol.updateUI();
						mpdArbol.validate();
					}
					graficarNiveles((Graphics2D) e);
				} else {
					if (mpdArbol.getPreferredSize().getHeight() < niveles * 100 + 20) {
						mpdArbol.setPreferredSize(new Dimension(mpdArbol
								.getPreferredSize().width, niveles * 100 + 20));
						mpdArbol.updateUI();
						mpdArbol.validate();
					}
					graficarArbol((Graphics2D) e);
				}
			}
		};
		radioNiveles = new javax.swing.JRadioButton();
		radioArbol = new javax.swing.JRadioButton();
		chkAltura = new javax.swing.JCheckBox();

		ctxAddSon.setText("Agregar hijo");
		ctxAddSon.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				mpdArbol.setPreferredSize(new Dimension(0, 0));
				ctxAddSonActionPerformed(evt);
			}
		});
		clickDerecho.add(ctxAddSon);

		ctxDeleteNode.setText("Borrar nodo");
		ctxDeleteNode.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				ctxDeleteNodeActionPerformed(evt);
			}
		});
		clickDerecho.add(ctxDeleteNode);

		setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

		panelDeFondo.setOpaque(false);

		setResizable(false);
		panelOperaciones.setBorder(new javax.swing.border.LineBorder(
				new java.awt.Color(0, 0, 0), 1, true));
		panelOperaciones.setOpaque(false);

		btnLoadTree.setFont(new java.awt.Font("DejaVu Sans", 1, 13));
		btnLoadTree.setText("Cargar Arbol");
		btnLoadTree.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				btnLoadTreeActionPerformed(evt);
			}
		});

		panelAdd.setBorder(javax.swing.BorderFactory.createTitledBorder(null,
				"Agregar Nodo",
				javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION,
				javax.swing.border.TitledBorder.DEFAULT_POSITION,
				new java.awt.Font("Dialog", 1, 12))); // NOI18N
		panelAdd.setOpaque(false);
		panelAdd.setPreferredSize(new java.awt.Dimension(17, 153));

		btnAddNode.setFont(new java.awt.Font("DejaVu Sans", 1, 13));
		btnAddNode.setText("Agregar");
		btnAddNode.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				btnAddNodeActionPerformed(evt);
			}
		});

		cbPadres.setOpaque(false);

		txtRotulo.setOpaque(false);

		lblRotulo.setFont(new java.awt.Font("DejaVu Sans", 1, 12));
		lblRotulo.setText("Rotulo");

		lblPadre.setFont(new java.awt.Font("DejaVu Sans", 1, 12));
		lblPadre.setText("Padre");

		javax.swing.GroupLayout panelAddLayout = new javax.swing.GroupLayout(
				panelAdd);
		panelAdd.setLayout(panelAddLayout);
		panelAddLayout
				.setHorizontalGroup(panelAddLayout
						.createParallelGroup(
								javax.swing.GroupLayout.Alignment.LEADING)
						.addGroup(
								panelAddLayout
										.createSequentialGroup()
										.addContainerGap()
										.addGroup(
												panelAddLayout
														.createParallelGroup(
																javax.swing.GroupLayout.Alignment.LEADING)
														.addComponent(
																btnAddNode,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																209,
																Short.MAX_VALUE)
														.addGroup(
																panelAddLayout
																		.createSequentialGroup()
																		.addGroup(
																				panelAddLayout
																						.createParallelGroup(
																								javax.swing.GroupLayout.Alignment.LEADING)
																						.addComponent(
																								lblRotulo)
																						.addComponent(
																								lblPadre))
																		.addGap(
																				85,
																				85,
																				85)
																		.addGroup(
																				panelAddLayout
																						.createParallelGroup(
																								javax.swing.GroupLayout.Alignment.TRAILING)
																						.addComponent(
																								txtRotulo,
																								javax.swing.GroupLayout.DEFAULT_SIZE,
																								78,
																								Short.MAX_VALUE)
																						.addComponent(
																								cbPadres,
																								0,
																								78,
																								Short.MAX_VALUE))))
										.addContainerGap()));
		panelAddLayout
				.setVerticalGroup(panelAddLayout
						.createParallelGroup(
								javax.swing.GroupLayout.Alignment.LEADING)
						.addGroup(
								panelAddLayout
										.createSequentialGroup()
										.addContainerGap()
										.addGroup(
												panelAddLayout
														.createParallelGroup(
																javax.swing.GroupLayout.Alignment.BASELINE)
														.addComponent(lblRotulo)
														.addComponent(
																txtRotulo,
																javax.swing.GroupLayout.PREFERRED_SIZE,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																javax.swing.GroupLayout.PREFERRED_SIZE))
										.addPreferredGap(
												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
										.addGroup(
												panelAddLayout
														.createParallelGroup(
																javax.swing.GroupLayout.Alignment.BASELINE)
														.addComponent(lblPadre)
														.addComponent(
																cbPadres,
																javax.swing.GroupLayout.PREFERRED_SIZE,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																javax.swing.GroupLayout.PREFERRED_SIZE))
										.addPreferredGap(
												javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
										.addComponent(btnAddNode)
										.addContainerGap(19, Short.MAX_VALUE)));

		panelEliminar.setBorder(javax.swing.BorderFactory.createTitledBorder(
				null, "Eliminar Nivel",
				javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION,
				javax.swing.border.TitledBorder.DEFAULT_POSITION,
				new java.awt.Font("Dialog", 1, 12))); // NOI18N
		panelEliminar.setOpaque(false);
		panelEliminar.setPreferredSize(new java.awt.Dimension(174, 98));

		btnDeleteLevel.setFont(new java.awt.Font("DejaVu Sans", 1, 13));
		btnDeleteLevel.setText("Eliminar");
		btnDeleteLevel.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				btnDeleteLevelActionPerformed(evt);
			}
		});

		cbNiveles.setOpaque(false);

		lblNivel.setFont(new java.awt.Font("DejaVu Sans", 1, 12));
		lblNivel.setText("Nivel");

		javax.swing.GroupLayout panelEliminarLayout = new javax.swing.GroupLayout(
				panelEliminar);
		panelEliminar.setLayout(panelEliminarLayout);
		panelEliminarLayout
				.setHorizontalGroup(panelEliminarLayout
						.createParallelGroup(
								javax.swing.GroupLayout.Alignment.LEADING)
						.addGroup(
								javax.swing.GroupLayout.Alignment.TRAILING,
								panelEliminarLayout
										.createSequentialGroup()
										.addContainerGap()
										.addGroup(
												panelEliminarLayout
														.createParallelGroup(
																javax.swing.GroupLayout.Alignment.TRAILING)
														.addComponent(
																btnDeleteLevel,
																javax.swing.GroupLayout.Alignment.LEADING,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																209,
																Short.MAX_VALUE)
														.addGroup(
																panelEliminarLayout
																		.createSequentialGroup()
																		.addComponent(
																				lblNivel,
																				javax.swing.GroupLayout.DEFAULT_SIZE,
																				129,
																				Short.MAX_VALUE)
																		.addGap(
																				26,
																				26,
																				26)
																		.addComponent(
																				cbNiveles,
																				javax.swing.GroupLayout.PREFERRED_SIZE,
																				54,
																				javax.swing.GroupLayout.PREFERRED_SIZE)))
										.addContainerGap()));
		panelEliminarLayout
				.setVerticalGroup(panelEliminarLayout
						.createParallelGroup(
								javax.swing.GroupLayout.Alignment.LEADING)
						.addGroup(
								panelEliminarLayout
										.createSequentialGroup()
										.addGroup(
												panelEliminarLayout
														.createParallelGroup(
																javax.swing.GroupLayout.Alignment.BASELINE)
														.addComponent(
																cbNiveles,
																javax.swing.GroupLayout.PREFERRED_SIZE,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																javax.swing.GroupLayout.PREFERRED_SIZE)
														.addComponent(lblNivel))
										.addPreferredGap(
												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
										.addComponent(
												btnDeleteLevel,
												javax.swing.GroupLayout.DEFAULT_SIZE,
												31, Short.MAX_VALUE)
										.addContainerGap()));

		panelAncCam.setBorder(javax.swing.BorderFactory.createTitledBorder(
				null, "Ancestro - Camino",
				javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION,
				javax.swing.border.TitledBorder.DEFAULT_POSITION,
				new java.awt.Font("Dialog", 1, 12))); // NOI18N
		panelAncCam.setOpaque(false);

		cbDesde.setOpaque(false);

		cbHasta.setOpaque(false);

		lblDesde.setFont(new java.awt.Font("DejaVu Sans", 1, 12));
		lblDesde.setText("Desde");

		lblHasta.setFont(new java.awt.Font("DejaVu Sans", 1, 12));
		lblHasta.setText("Hasta");

		panelMostrarAC.setBorder(javax.swing.BorderFactory.createTitledBorder(
				null, "Mostrar",
				javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION,
				javax.swing.border.TitledBorder.DEFAULT_POSITION,
				new java.awt.Font("Dialog", 1, 11))); // NOI18N
		panelMostrarAC.setOpaque(false);

		chkCamino.setFont(new java.awt.Font("DejaVu Sans", 1, 12));
		chkCamino.setText("Marcar camino");
		chkCamino.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				chkCaminoActionPerformed(evt);
			}
		});

		chkAncestro.setFont(new java.awt.Font("DejaVu Sans", 1, 12));
		chkAncestro.setText("Ancestro comun");
		chkAncestro.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				chkAncestroActionPerformed(evt);
			}
		});

		javax.swing.GroupLayout panelMostrarACLayout = new javax.swing.GroupLayout(
				panelMostrarAC);
		panelMostrarAC.setLayout(panelMostrarACLayout);
		panelMostrarACLayout
				.setHorizontalGroup(panelMostrarACLayout
						.createParallelGroup(
								javax.swing.GroupLayout.Alignment.LEADING)
						.addGroup(
								panelMostrarACLayout
										.createSequentialGroup()
										.addContainerGap()
										.addGroup(
												panelMostrarACLayout
														.createParallelGroup(
																javax.swing.GroupLayout.Alignment.LEADING)
														.addComponent(
																chkAncestro)
														.addComponent(chkCamino))
										.addContainerGap(48, Short.MAX_VALUE)));
		panelMostrarACLayout
				.setVerticalGroup(panelMostrarACLayout
						.createParallelGroup(
								javax.swing.GroupLayout.Alignment.LEADING)
						.addGroup(
								panelMostrarACLayout
										.createSequentialGroup()
										.addComponent(chkAncestro)
										.addPreferredGap(
												javax.swing.LayoutStyle.ComponentPlacement.RELATED,
												15, Short.MAX_VALUE)
										.addComponent(chkCamino)));

		javax.swing.GroupLayout panelAncCamLayout = new javax.swing.GroupLayout(
				panelAncCam);
		panelAncCam.setLayout(panelAncCamLayout);
		panelAncCamLayout
				.setHorizontalGroup(panelAncCamLayout
						.createParallelGroup(
								javax.swing.GroupLayout.Alignment.LEADING)
						.addGroup(
								panelAncCamLayout
										.createSequentialGroup()
										.addContainerGap()
										.addGroup(
												panelAncCamLayout
														.createParallelGroup(
																javax.swing.GroupLayout.Alignment.LEADING)
														.addGroup(
																javax.swing.GroupLayout.Alignment.TRAILING,
																panelAncCamLayout
																		.createSequentialGroup()
																		.addGroup(
																				panelAncCamLayout
																						.createParallelGroup(
																								javax.swing.GroupLayout.Alignment.LEADING)
																						.addComponent(
																								lblDesde)
																						.addComponent(
																								lblHasta))
																		.addPreferredGap(
																				javax.swing.LayoutStyle.ComponentPlacement.RELATED,
																				111,
																				Short.MAX_VALUE)
																		.addGroup(
																				panelAncCamLayout
																						.createParallelGroup(
																								javax.swing.GroupLayout.Alignment.TRAILING,
																								false)
																						.addComponent(
																								cbHasta,
																								0,
																								javax.swing.GroupLayout.DEFAULT_SIZE,
																								Short.MAX_VALUE)
																						.addComponent(
																								cbDesde,
																								0,
																								53,
																								Short.MAX_VALUE)))
														.addComponent(
																panelMostrarAC,
																javax.swing.GroupLayout.Alignment.TRAILING,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																Short.MAX_VALUE))
										.addContainerGap()));
		panelAncCamLayout
				.setVerticalGroup(panelAncCamLayout
						.createParallelGroup(
								javax.swing.GroupLayout.Alignment.LEADING)
						.addGroup(
								panelAncCamLayout
										.createSequentialGroup()
										.addGroup(
												panelAncCamLayout
														.createParallelGroup(
																javax.swing.GroupLayout.Alignment.BASELINE)
														.addComponent(lblDesde)
														.addComponent(
																cbDesde,
																javax.swing.GroupLayout.PREFERRED_SIZE,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																javax.swing.GroupLayout.PREFERRED_SIZE))
										.addPreferredGap(
												javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
										.addGroup(
												panelAncCamLayout
														.createParallelGroup(
																javax.swing.GroupLayout.Alignment.BASELINE)
														.addComponent(lblHasta)
														.addComponent(
																cbHasta,
																javax.swing.GroupLayout.PREFERRED_SIZE,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																javax.swing.GroupLayout.PREFERRED_SIZE))
										.addPreferredGap(
												javax.swing.LayoutStyle.ComponentPlacement.RELATED,
												58, Short.MAX_VALUE)
										.addComponent(
												panelMostrarAC,
												javax.swing.GroupLayout.PREFERRED_SIZE,
												javax.swing.GroupLayout.DEFAULT_SIZE,
												javax.swing.GroupLayout.PREFERRED_SIZE)
										.addContainerGap()));

		btnEliminarArbol.setFont(new java.awt.Font("DejaVu Sans", 1, 13));
		btnEliminarArbol.setText("Eliminar Arbol");

		btnEliminarArbol.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				btnEliminarArbolActionPerformed(evt);
			}
		});

		javax.swing.GroupLayout panelOperacionesLayout = new javax.swing.GroupLayout(
				panelOperaciones);
		panelOperaciones.setLayout(panelOperacionesLayout);
		panelOperacionesLayout
				.setHorizontalGroup(panelOperacionesLayout
						.createParallelGroup(
								javax.swing.GroupLayout.Alignment.LEADING)
						.addGroup(
								panelOperacionesLayout
										.createSequentialGroup()
										.addContainerGap()
										.addGroup(
												panelOperacionesLayout
														.createParallelGroup(
																javax.swing.GroupLayout.Alignment.TRAILING)
														.addComponent(
																panelAncCam,
																javax.swing.GroupLayout.Alignment.LEADING,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																Short.MAX_VALUE)
														.addComponent(
																btnEliminarArbol,
																javax.swing.GroupLayout.Alignment.LEADING,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																245,
																Short.MAX_VALUE)
														.addComponent(
																btnLoadTree,
																javax.swing.GroupLayout.Alignment.LEADING,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																245,
																Short.MAX_VALUE)
														.addComponent(
																panelAdd,
																javax.swing.GroupLayout.Alignment.LEADING,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																245,
																Short.MAX_VALUE)
														.addComponent(
																panelEliminar,
																javax.swing.GroupLayout.Alignment.LEADING,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																245,
																Short.MAX_VALUE))
										.addContainerGap()));
		panelOperacionesLayout
				.setVerticalGroup(panelOperacionesLayout
						.createParallelGroup(
								javax.swing.GroupLayout.Alignment.LEADING)
						.addGroup(
								panelOperacionesLayout
										.createSequentialGroup()
										.addContainerGap()
										.addComponent(
												btnLoadTree,
												javax.swing.GroupLayout.PREFERRED_SIZE,
												31,
												javax.swing.GroupLayout.PREFERRED_SIZE)
										.addPreferredGap(
												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
										.addComponent(
												btnEliminarArbol,
												javax.swing.GroupLayout.PREFERRED_SIZE,
												28,
												javax.swing.GroupLayout.PREFERRED_SIZE)
										.addPreferredGap(
												javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
										.addComponent(
												panelAdd,
												javax.swing.GroupLayout.PREFERRED_SIZE,
												javax.swing.GroupLayout.DEFAULT_SIZE,
												javax.swing.GroupLayout.PREFERRED_SIZE)
										.addPreferredGap(
												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
										.addComponent(
												panelEliminar,
												javax.swing.GroupLayout.PREFERRED_SIZE,
												101,
												javax.swing.GroupLayout.PREFERRED_SIZE)
										.addPreferredGap(
												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
										.addComponent(
												panelAncCam,
												javax.swing.GroupLayout.PREFERRED_SIZE,
												javax.swing.GroupLayout.DEFAULT_SIZE,
												javax.swing.GroupLayout.PREFERRED_SIZE)
										.addContainerGap(84, Short.MAX_VALUE)));

		panelGraficos.setBorder(new javax.swing.border.LineBorder(
				new java.awt.Color(0, 0, 0), 1, true));
		panelGraficos.setOpaque(false);

		panelRecorridos.setBorder(javax.swing.BorderFactory.createTitledBorder(
				null, "Grafico de recorrido",
				javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION,
				javax.swing.border.TitledBorder.DEFAULT_POSITION,
				new java.awt.Font("Dialog", 1, 12))); // NOI18N
		panelRecorridos.setOpaque(false);

		panelTipoRecorrido.setOpaque(false);

		radioPre.setFont(new java.awt.Font("DejaVu Sans", 1, 12));
		radioPre.setSelected(true);
		radioPre.setText("Pre-orden");
		radioPre.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				radioPreActionPerformed(evt);
			}
		});

		radioPos.setFont(new java.awt.Font("DejaVu Sans", 1, 12));
		radioPos.setText("Pos-orden");
		radioPos.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				radioPosActionPerformed(evt);
			}
		});

		javax.swing.GroupLayout panelTipoRecorridoLayout = new javax.swing.GroupLayout(
				panelTipoRecorrido);
		panelTipoRecorrido.setLayout(panelTipoRecorridoLayout);
		panelTipoRecorridoLayout.setHorizontalGroup(panelTipoRecorridoLayout
				.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
				.addGroup(
						javax.swing.GroupLayout.Alignment.TRAILING,
						panelTipoRecorridoLayout.createSequentialGroup()
								.addContainerGap(14, Short.MAX_VALUE)
								.addComponent(radioPre).addContainerGap())
				.addGroup(
						panelTipoRecorridoLayout.createSequentialGroup()
								.addContainerGap().addComponent(radioPos)
								.addContainerGap(
										javax.swing.GroupLayout.DEFAULT_SIZE,
										Short.MAX_VALUE)));
		panelTipoRecorridoLayout
				.setVerticalGroup(panelTipoRecorridoLayout
						.createParallelGroup(
								javax.swing.GroupLayout.Alignment.LEADING)
						.addGroup(
								javax.swing.GroupLayout.Alignment.TRAILING,
								panelTipoRecorridoLayout
										.createSequentialGroup()
										.addGap(12, 12, 12)
										.addComponent(
												radioPre,
												javax.swing.GroupLayout.DEFAULT_SIZE,
												22, Short.MAX_VALUE)
										.addPreferredGap(
												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
										.addComponent(
												radioPos,
												javax.swing.GroupLayout.DEFAULT_SIZE,
												javax.swing.GroupLayout.DEFAULT_SIZE,
												Short.MAX_VALUE).addGap(18, 18,
												18)));

		scrollRecorrido
				.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
		scrollRecorrido.setOpaque(false);

		mpdRecorrido.setOpaque(false);

		mpdRecorrido.setPreferredSize(new Dimension(0, 0));

		javax.swing.GroupLayout mpdRecorridoLayout = new javax.swing.GroupLayout(
				mpdRecorrido);
		mpdRecorrido.setLayout(mpdRecorridoLayout);
		mpdRecorridoLayout.setHorizontalGroup(mpdRecorridoLayout
				.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
				.addGap(0, 570, Short.MAX_VALUE));
		mpdRecorridoLayout.setVerticalGroup(mpdRecorridoLayout
				.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
				.addGap(0, 100, Short.MAX_VALUE));

		scrollRecorrido.setViewportView(mpdRecorrido);

		javax.swing.GroupLayout panelRecorridosLayout = new javax.swing.GroupLayout(
				panelRecorridos);
		panelRecorridos.setLayout(panelRecorridosLayout);
		panelRecorridosLayout
				.setHorizontalGroup(panelRecorridosLayout
						.createParallelGroup(
								javax.swing.GroupLayout.Alignment.LEADING)
						.addGroup(
								panelRecorridosLayout
										.createSequentialGroup()
										.addComponent(
												panelTipoRecorrido,
												javax.swing.GroupLayout.PREFERRED_SIZE,
												javax.swing.GroupLayout.DEFAULT_SIZE,
												javax.swing.GroupLayout.PREFERRED_SIZE)
										.addPreferredGap(
												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
										.addComponent(
												scrollRecorrido,
												javax.swing.GroupLayout.DEFAULT_SIZE,
												548, Short.MAX_VALUE)
										.addContainerGap()));
		panelRecorridosLayout
				.setVerticalGroup(panelRecorridosLayout
						.createParallelGroup(
								javax.swing.GroupLayout.Alignment.LEADING)
						.addGroup(
								panelRecorridosLayout
										.createSequentialGroup()
										.addContainerGap()
										.addGroup(
												panelRecorridosLayout
														.createParallelGroup(
																javax.swing.GroupLayout.Alignment.CENTER)
														.addComponent(
																panelTipoRecorrido,
																javax.swing.GroupLayout.PREFERRED_SIZE,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																javax.swing.GroupLayout.PREFERRED_SIZE)
														.addComponent(
																scrollRecorrido,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																86,
																Short.MAX_VALUE))
										.addContainerGap()));

		panelArbol.setBorder(javax.swing.BorderFactory.createTitledBorder(null,
				"Grafico",
				javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION,
				javax.swing.border.TitledBorder.DEFAULT_POSITION,
				new java.awt.Font("Dialog", 1, 12))); // NOI18N
		panelArbol.setOpaque(false);

		scrollArbol.setAutoscrolls(true);
		scrollArbol.setOpaque(false);

		mpdArbol.addMouseListener(new java.awt.event.MouseAdapter() {
			public void mouseClicked(java.awt.event.MouseEvent evt) {
				mpdArbolMouseClicked(evt);
			}
		});
		mpdArbol
				.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
					public void mouseMoved(java.awt.event.MouseEvent evt) {
						mpdArbolMouseMoved(evt);
					}
				});
		mpdArbol.setPreferredSize(new Dimension(0, 0));

		javax.swing.GroupLayout mpdArbolLayout = new javax.swing.GroupLayout(
				mpdArbol);
		mpdArbol.setLayout(mpdArbolLayout);
		mpdArbolLayout.setHorizontalGroup(mpdArbolLayout.createParallelGroup(
				javax.swing.GroupLayout.Alignment.LEADING).addGap(0, 685,
				Short.MAX_VALUE));
		mpdArbolLayout.setVerticalGroup(mpdArbolLayout.createParallelGroup(
				javax.swing.GroupLayout.Alignment.LEADING).addGap(0, 412,
				Short.MAX_VALUE));

		scrollArbol.setViewportView(mpdArbol);

		radioNiveles.setFont(new java.awt.Font("DejaVu Sans", 1, 12));
		radioNiveles.setText("Mostrar Niveles");
		radioNiveles.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				radioNivelesActionPerformed(evt);
			}
		});

		radioArbol.setFont(new java.awt.Font("DejaVu Sans", 1, 12));
		radioArbol.setSelected(true);
		radioArbol.setText("Mostrar Arbol");
		radioArbol.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				radioArbolActionPerformed(evt);
			}
		});

		chkAltura.setFont(new java.awt.Font("DejaVu Sans", 1, 12)); // NOI18N
		chkAltura.setText("Mostrar altura");

		javax.swing.GroupLayout panelArbolLayout = new javax.swing.GroupLayout(
				panelArbol);
		panelArbol.setLayout(panelArbolLayout);
		panelArbolLayout
				.setHorizontalGroup(panelArbolLayout
						.createParallelGroup(
								javax.swing.GroupLayout.Alignment.LEADING)
						.addGroup(
								panelArbolLayout
										.createSequentialGroup()
										.addContainerGap()
										.addGroup(
												panelArbolLayout
														.createParallelGroup(
																javax.swing.GroupLayout.Alignment.LEADING)
														.addGroup(
																panelArbolLayout
																		.createSequentialGroup()
																		.addComponent(
																				scrollArbol,
																				javax.swing.GroupLayout.DEFAULT_SIZE,
																				664,
																				Short.MAX_VALUE)
																		.addGap(
																				34,
																				34,
																				34))
														.addGroup(
																panelArbolLayout
																		.createSequentialGroup()
																		.addComponent(
																				chkAltura)
																		.addGap(
																				71,
																				71,
																				71)
																		.addComponent(
																				radioArbol,
																				javax.swing.GroupLayout.DEFAULT_SIZE,
																				javax.swing.GroupLayout.DEFAULT_SIZE,
																				Short.MAX_VALUE)
																		.addGap(
																				18,
																				18,
																				18)
																		.addComponent(
																				radioNiveles,
																				javax.swing.GroupLayout.DEFAULT_SIZE,
																				javax.swing.GroupLayout.DEFAULT_SIZE,
																				Short.MAX_VALUE)
																		.addGap(
																				226,
																				226,
																				226)))));
		panelArbolLayout
				.setVerticalGroup(panelArbolLayout
						.createParallelGroup(
								javax.swing.GroupLayout.Alignment.LEADING)
						.addGroup(
								javax.swing.GroupLayout.Alignment.TRAILING,
								panelArbolLayout
										.createSequentialGroup()
										.addContainerGap()
										.addComponent(
												scrollArbol,
												javax.swing.GroupLayout.DEFAULT_SIZE,
												414, Short.MAX_VALUE)
										.addPreferredGap(
												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
										.addGroup(
												panelArbolLayout
														.createParallelGroup(
																javax.swing.GroupLayout.Alignment.BASELINE)
														.addComponent(
																radioArbol,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																Short.MAX_VALUE)
														.addComponent(
																radioNiveles,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																Short.MAX_VALUE)
														.addComponent(chkAltura))
										.addContainerGap()));

		javax.swing.GroupLayout panelGraficosLayout = new javax.swing.GroupLayout(
				panelGraficos);
		panelGraficos.setLayout(panelGraficosLayout);
		panelGraficosLayout
				.setHorizontalGroup(panelGraficosLayout
						.createParallelGroup(
								javax.swing.GroupLayout.Alignment.LEADING)
						.addGroup(
								panelGraficosLayout
										.createSequentialGroup()
										.addContainerGap()
										.addGroup(
												panelGraficosLayout
														.createParallelGroup(
																javax.swing.GroupLayout.Alignment.TRAILING)
														.addComponent(
																panelArbol,
																javax.swing.GroupLayout.Alignment.LEADING,
																0, 699,
																Short.MAX_VALUE)
														.addComponent(
																panelRecorridos,
																javax.swing.GroupLayout.Alignment.LEADING,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																Short.MAX_VALUE))
										.addContainerGap()));
		panelGraficosLayout
				.setVerticalGroup(panelGraficosLayout
						.createParallelGroup(
								javax.swing.GroupLayout.Alignment.LEADING)
						.addGroup(
								panelGraficosLayout
										.createSequentialGroup()
										.addContainerGap()
										.addComponent(
												panelArbol,
												javax.swing.GroupLayout.PREFERRED_SIZE,
												javax.swing.GroupLayout.DEFAULT_SIZE,
												javax.swing.GroupLayout.PREFERRED_SIZE)
										.addPreferredGap(
												javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
										.addComponent(
												panelRecorridos,
												javax.swing.GroupLayout.PREFERRED_SIZE,
												javax.swing.GroupLayout.DEFAULT_SIZE,
												javax.swing.GroupLayout.PREFERRED_SIZE)
										.addContainerGap()));

		javax.swing.GroupLayout panelDeFondoLayout = new javax.swing.GroupLayout(
				panelDeFondo);
		panelDeFondo.setLayout(panelDeFondoLayout);
		panelDeFondoLayout.setHorizontalGroup(panelDeFondoLayout
				.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
				.addGroup(
						panelDeFondoLayout.createSequentialGroup()
								.addContainerGap().addComponent(
										panelOperaciones,
										javax.swing.GroupLayout.PREFERRED_SIZE,
										javax.swing.GroupLayout.DEFAULT_SIZE,
										javax.swing.GroupLayout.PREFERRED_SIZE)
								.addGap(18, 18, 18).addComponent(panelGraficos,
										javax.swing.GroupLayout.DEFAULT_SIZE,
										javax.swing.GroupLayout.DEFAULT_SIZE,
										Short.MAX_VALUE).addContainerGap()));
		panelDeFondoLayout
				.setVerticalGroup(panelDeFondoLayout
						.createParallelGroup(
								javax.swing.GroupLayout.Alignment.LEADING)
						.addGroup(
								javax.swing.GroupLayout.Alignment.TRAILING,
								panelDeFondoLayout
										.createSequentialGroup()
										.addContainerGap()
										.addGroup(
												panelDeFondoLayout
														.createParallelGroup(
																javax.swing.GroupLayout.Alignment.TRAILING)
														.addComponent(
																panelOperaciones,
																javax.swing.GroupLayout.Alignment.LEADING,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																javax.swing.GroupLayout.DEFAULT_SIZE,
																Short.MAX_VALUE)
														.addComponent(
																panelGraficos,
																javax.swing.GroupLayout.Alignment.LEADING,
																0, 685,
																Short.MAX_VALUE))
										.addContainerGap()));

		javax.swing.GroupLayout layout = new javax.swing.GroupLayout(
				getContentPane());
		getContentPane().setLayout(layout);
		layout.setHorizontalGroup(layout.createParallelGroup(
				javax.swing.GroupLayout.Alignment.LEADING).addComponent(
				panelDeFondo, javax.swing.GroupLayout.DEFAULT_SIZE,
				javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE));
		layout.setVerticalGroup(layout.createParallelGroup(
				javax.swing.GroupLayout.Alignment.LEADING).addComponent(
				panelDeFondo, javax.swing.GroupLayout.DEFAULT_SIZE,
				javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE));

		pack();
	}// </editor-fold>//GEN-END:initComponents

	protected void btnEliminarArbolActionPerformed(ActionEvent evt) {
		TestingApplication.miArbol = null;
		btnLoadTree.setEnabled(true);
		arbol = null;
		mpdArbol.repaint();
		mpdRecorrido.repaint();
	}

	private void mpdArbolMouseClicked(java.awt.event.MouseEvent evt) {// GEN-FIRST:event_mpdArbolMouseClicked
		// Entra si el click es el derecho
		if (arbol != null) {
			if (evt.getButton() == evt.BUTTON3)
				if (radioArbol.isSelected()) {
					// Crea una elipse y verifica si el mouse esta en uno de los
					// nodos
					Ellipse2D elipse;
					for (Position<Character> pos : arbol.positions()) {
						TNode<Character> nodo = (TNode<Character>) pos;
						// crea una elipse que representa al dibujo del nodo
						elipse = new Ellipse2D.Double(nodo.getCorner().getX(),
								nodo.getCorner().getY(), nodoSize.getWidth(),
								nodoSize.getHeight());
						// si el mouse esta adentro de la elipse
						if (elipse.contains(evt.getPoint())) {
							clickDerecho.show(mpdArbol, evt.getPoint().x, evt
									.getPoint().y);
							// si la encuentra no busca mas
							break;
						}
					}
					// mousePoint guarda la posicion del mouse para imprimir el
					// menu
					mousePoint = evt.getPoint();
					// repinta el arbol
					mpdArbol.repaint();
				}
		}
	}// GEN-LAST:event_mpdArbolMouseClicked

	private void mpdArbolMouseMoved(java.awt.event.MouseEvent evt) {// GEN-FIRST:event_mpdArbolMouseMoved
		if (radioArbol.isSelected()) {
			// si hay un nodo bajo el cursor drawSelected lo dibuja
			drawSelected(evt.getPoint(), (Graphics2D) mpdArbol.getGraphics());
		}
	}// GEN-LAST:event_mpdArbolMouseMoved

	private void ctxDeleteNodeActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_ctxDeleteNodeActionPerformed
		Ellipse2D elipse;
		/*
		 * crea una elipse que representa al nodo y verifica si mousePoint
		 * (guarda el lugar donde se apreto el click para abrir el menu)
		 * pertenece a ella
		 */
		for (Position<Character> pos : arbol.positions()) {

			TNode<Character> nodo = (TNode<Character>) pos;

			elipse = new Ellipse2D.Double(nodo.getCorner().getX(), nodo
					.getCorner().getY(), nodoSize.getWidth(), nodoSize
					.getHeight());

			if (elipse.contains(mousePoint)) {
				try {
					// muestra un mensaje de error si se quiere borrar la raiz
					if (arbol.isRoot(pos))
						JOptionPane.showMessageDialog(null,
								"No se puede borrar la raiz.",
								"Error al borrar nodo",
								JOptionPane.ERROR_MESSAGE);
					else {
						// borra el nodo y oculta el menu
						TestingApplication.borrarNodo(pos);
						clickDerecho.setVisible(false);
						// recalcula los centros de los nodos luego de borrar
						TestingApplication.calcularCentros(mpdArbol.getWidth(),
								new Point2D.Double(0, 20),
								(TNode<Character>) arbol.root());
						// actualiza el mapeo que contiene la altura de cada
						// nodo
						TestingApplication.actualizarMapeo();
						// actualiza todos los comboboxes
						actualizarCombos();
						// repinta las dos areas de graficos
						mpdArbol.repaint();
						mpdRecorrido.repaint();
						/*
						 * last_draw y last_char almacenan el ultimo nodo
						 * dibujado su letra
						 */
						last_draw = null;
						last_char = null;
					}
				} catch (InvalidPositionException e) {
					// las posiciones son validas porque las genera positions()
					System.out
							.println("Esta excepcion no deberia llegar a dispararse.");
				} catch (EmptyTreeException e) {
					// el arbol no puede estar vacio porque ninguna elipse lo
					// contendria
					System.out
							.println("Esta excepcion no deberia llegar a dispararse.");
				}
				break;
			}
		}
	}// GEN-LAST:event_ctxDeleteNodeActionPerformed

	private void ctxAddSonActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_ctxAddSonActionPerformed
		// se genera la ventana para ingresar el caracter
		String response = JOptionPane.showInputDialog(null, "Agregar hijo",
				"Ingrese el nuevo rotulo:", JOptionPane.QUESTION_MESSAGE);
		// si la entrada es correcta
		if (response != null) {
			Character para_agregar = response.charAt(0);
			if (!existeEnArbol(para_agregar)) {
				// agrega el nodo al arbol
				TestingApplication.agregarNodo(para_agregar, last_char);
				try {
					TestingApplication.calcularCentros(mpdArbol.getWidth(),
							new Point2D.Double(0, 20), (TNode<Character>) arbol
									.root());
				} catch (InvalidPositionException e) {
					// la raiz siempre es una posicion correcta si el arbol no
					// esta vacio
					System.out
							.println("Esta excepcion no deberia llegar a dispararse.");
				} catch (EmptyTreeException e) {
					// el arbol no puede estar vacio porque ninguna elipse lo
					// contendria
					System.out
							.println("Esta excepcion no deberia llegar a dispararse.");
				}
				// actualiza el mapeo, los combos y repinta las areas de dibujo
				TestingApplication.actualizarMapeo();
				actualizarCombos();
				mpdArbol.repaint();
				mpdRecorrido.repaint();

			} else {
				// si el rotulo ya pertenece al arbol se crea un mensaje de
				// error
				JOptionPane.showMessageDialog(null,
						"El rotulo ingresado ya pertenece al arbol.", "Error",
						JOptionPane.ERROR_MESSAGE);
			}
		}
	}// GEN-LAST:event_ctxAddSonActionPerformed

	/**
	 * Se encarga de dibujar el nodo que se encuentra debajo del puntero. Es
	 * llamado por el evento MouseMoved del panel de dibujo
	 * 
	 * @param point
	 *            Posicion del puntero
	 * @param e
	 *            Lugar donde se dibujara
	 */
	private void drawSelected(Point2D point, Graphics2D e) {
		if (arbol != null && !arbol.isEmpty()) {
			Ellipse2D elipse;
			// verifica si se realizo algun cambio
			boolean dibuje = false;
			/*
			 * last_draw contiene la esquina del ultimo nodo dibujado se utiliza
			 * para no volver a dibujar el nodo si todavia se esta dentro de el
			 */
			if (last_draw != null) {
				/*
				 * se crea una elipse que representa al ultimo nodo dibujado si
				 * todavia se esta en ese nodo, no hace nada sino oculta el menu
				 * contextual
				 */
				elipse = new Ellipse2D.Double(last_draw.getX(), last_draw
						.getY(), 48, 48);
				if (elipse.contains(point))
					return;
				else {
					clickDerecho.setVisible(false);
					// dibuja el nodo del color inicial
					dibujarNodo(green, last_draw, last_char.toString(), e);
					if (chkCamino.isSelected()) {
						resaltarCamino(e);
					}
					if (chkAncestro.isSelected()) {
						resaltarAncestro(e);
					}
				}
			}
			try {
				// verifica si el puntero esta en un nuevo nodo
				for (Position<Character> pos : arbol.positions()) {
					TNode<Character> nodo = (TNode<Character>) pos;
					elipse = new Ellipse2D.Double(nodo.getCorner().getX(), nodo
							.getCorner().getY(), 48, 48);
					// si el puntero esta en un nodo
					if (elipse.contains(point)) {
						// dibuja el nodo resaltado y guarda su posicion y
						// caracter
						String str = ((Integer) arbol.height(nodo)).toString();
						if (chkAltura.isSelected())

							dibujarNodo(red, nodo.getCorner(), str, e);

						last_char = nodo.element();
						last_draw = nodo.getCorner();
						dibuje = true;
						// si esta en un nodo, termina
						break;
					}
				}
				// si no dibujo un nodo entonces el ultimo nodo dibujado es nulo
				if (!dibuje) {
					last_draw = null;
				}
			} catch (InvalidPositionException e1) {
				// las posiciones son validas porque las genera positions()
				System.out.println("Esta excepcion no deberia dispararse.");
			}
		}
	}

	/**
	 * Dibuja un nodo en una posicion determinada a partir de la esquina
	 * superior izquierda
	 * 
	 * @param dibujo
	 *            Imagen a dibujar
	 * @param corner
	 *            Esquina superior izquierda
	 * @param texto
	 *            Texto a dibujar
	 * @param e
	 *            Lugar donde se dibujara
	 */
	private void dibujarNodo(Image dibujo, Point2D corner, String texto,
			Graphics2D e) {
		// dibuja un nodo a partir de una esquina, con un determinado texto en
		// un area determinada
		e.drawImage(dibujo, (int) corner.getX(), (int) corner.getY(), null);
		e.setFont(new Font(e.getFont().toString(), Font.BOLD, 14));
		e.setColor(Color.white);
		// dibuja el caracter con ajustes para centrar
		e.drawString(texto, (int) (corner.getX() + 48 / 2 - 5), (int) (corner
				.getY() + 48 / 2 + 5));
	}

	private void chkAncestroActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_chkAncestroActionPerformed
		mpdArbol.repaint();
	}// GEN-LAST:event_chkAncestroActionPerformed

	private void chkCaminoActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_chkCaminoActionPerformed
		mpdArbol.repaint();
	}// GEN-LAST:event_chkCaminoActionPerformed

	private void radioArbolActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_radioArbolActionPerformed
		// convierte el radiobutton en intercambiable con el de niveles
		if (!radioArbol.isSelected()) {
			radioArbol.setSelected(true);
		} else {
			radioNiveles.setSelected(false);
			radioArbol.setSelected(true);
			mpdArbol.repaint();
		}
	}// GEN-LAST:event_radioArbolActionPerformed

	private void radioNivelesActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_radioNivelesActionPerformed
		// convierte el radiobutton en intercambiable con el de padres
		if (!radioNiveles.isSelected()) {
			radioNiveles.setSelected(true);
		} else {
			radioArbol.setSelected(false);
			radioNiveles.setSelected(true);
			mpdArbol.repaint();
		}
	}// GEN-LAST:event_radioNivelesActionPerformed

	private void radioPosActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_jRadioButton2ActionPerformed
		// convierte el radiobutton en intercambiable con el de preorden
		if (!radioPos.isSelected()) {
			radioPos.setSelected(true);
		} else {
			radioPos.setSelected(true);
			radioPre.setSelected(false);
			mpdRecorrido.repaint();
		}
	}// GEN-LAST:event_jRadioButton2ActionPerformed

	private void radioPreActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_jRadioButton1ActionPerformed
		// convierte el radiobutton en intercambiable con el de posorden
		if (!radioPre.isSelected()) {
			radioPre.setSelected(true);
		} else {
			radioPre.setSelected(true);
			radioPos.setSelected(false);
			mpdRecorrido.repaint();
		}
	}// GEN-LAST:event_jRadioButton1ActionPerformed

	private void btnLoadTreeActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_btnLoadTreeActionPerformed
		// pide el rotulo de la raiz
		String response = JOptionPane.showInputDialog(null,
				"Rotulo de la raiz", "Ingrese el rotulo de la raiz",
				JOptionPane.QUESTION_MESSAGE);
		// si se escribio algo
		if (response != null && !response.equals("")) {
			TestingApplication.cargarArbol(response.charAt(0));
			btnLoadTree.setEnabled(false);

			cbPadres.addItem(response.charAt(0));
			// se inicializa el arbol
			TestingApplication.cargarArbol(response.charAt(0));
			arbol = TestingApplication.miArbol;
			niveles = 0;
			cbNiveles.addItem(0);
			txtRotulo.requestFocus();
			try {
				// se calculan los centros de los nodos
				TestingApplication.calcularCentros(mpdArbol.getWidth(),
						new Point2D.Double(0, 20), (TNode<Character>) arbol
								.root());
			} catch (InvalidPositionException e) {
				System.out.println("Esta excepcion no deberia dispararse");
			} catch (EmptyTreeException e) {
				System.out.println("Esta excepcion no deberia dispararse");
			}
			TestingApplication.actualizarMapeo();
			actualizarCombos();
			mpdArbol.repaint();
			mpdRecorrido.repaint();
		}
	}// GEN-LAST:event_btnLoadTreeActionPerformed

	private void btnAddNodeActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_btnAddNodeActionPerformed
		// si se escribio algo en el campo de texto y el arbol esta inicializado
		if (!txtRotulo.getText().equals("") && arbol != null) {
			// si no existe el rotulo
			if (!existeEnArbol(txtRotulo.getText().charAt(0))) {
				if (!txtRotulo.getText().equals("")) {
					Character nuevo = txtRotulo.getText().charAt(0);
					// se agrega el nodo nuevo
					TestingApplication.agregarNodo(nuevo, (Character) cbPadres
							.getSelectedItem());
					try {
						// se recalculan los centros
						TestingApplication.calcularCentros(mpdArbol.getWidth(),
								new Point2D.Double(0, 20),
								(TNode<Character>) arbol.root());
					} catch (InvalidPositionException e) {
						System.out
								.println("Esta excepcion no deberia dispararse");
					} catch (EmptyTreeException e) {
						System.out
								.println("Esta excepcion no deberia dispararse");

					}
					// se actualiza el mapeo
					TestingApplication.actualizarMapeo();
					actualizarCombos();
					cbPadres.setSelectedItem(nuevo);
					txtRotulo.setText("");
					// se repintan las areas de dibujo
					mpdArbol.repaint();
					mpdRecorrido.repaint();
				}
			} else {
				JOptionPane.showMessageDialog(null,
						"El rotulo ingresado ya pertenece al arbol.", "Error",
						JOptionPane.ERROR_MESSAGE);
			}
		}
	}// GEN-LAST:event_btnAddNodeActionPerformed

	/**
	 * Verifica si el caracter ya existe en el arbol
	 * 
	 * @param caracter
	 *            Caracter a buscar
	 * @return true si ya existe, false en caso contrario
	 */
	private boolean existeEnArbol(Character caracter) {
		for (Position<Character> pos : arbol.positions())
			if (pos.element().equals(caracter))
				return true;
		return false;
	}

	private void btnDeleteLevelActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_btnDeleteLevelActionPerformed
		// si el arbol esta inicializado
		if (arbol != null) {
			// si tiene solo la raiz
			if (niveles == 1)
				JOptionPane.showMessageDialog(null,
						"No se puede borrar la raiz.", "Error al borrar nodo",
						JOptionPane.ERROR_MESSAGE);
			else {
				try {
					// almacena la pila q debera pintarse
					pila_a_pintar = TestingApplication
							.eliminarNivel((Integer) cbNiveles
									.getSelectedItem());
					niveles--;
					// se recalculan los centros
					TestingApplication.calcularCentros(mpdArbol.getWidth(),
							new Point2D.Double(0, 20), (TNode<Character>) arbol
									.root());
					// se actualizan los combos
					actualizarCombos();
					// se repintan las areas de dibujo
					mpdArbol.repaint();
					mpdRecorrido.repaint();
					// se actualiza el mapeo
					TestingApplication.actualizarMapeo();
					// lanza la nueva ventana mostrando los elementos eliminados
					VentanaPila ventana = new VentanaPila(this) {

						public void paint(Graphics e) {
							e.drawImage(background, 0, 0, null);
						}
					};
					ventana.setTitle("Elementos eliminados");
					ventana.setVisible(true);
				} catch (EmptyTreeException e) {
					System.out.println("Esta excepcion no deberia dispararse");

				} catch (InvalidLevelException e) {
					System.out.println("Esta excepcion no deberia dispararse");

				} catch (InvalidPositionException e) {
					System.out.println("Esta excepcion no deberia dispararse");
				}
			}
		}
	}// GEN-LAST:event_btnDeleteLevelActionPerformed

	/**
	 * Actualiza todos los comboboxes
	 */
	private void actualizarCombos() {
		cbNiveles.removeAllItems();
		int cantNiveles = arbol.contarNiveles();
		for (int i = 1; i < cantNiveles; i++) {
			cbNiveles.addItem(i);
		}
		niveles = cantNiveles;
		cbPadres.removeAllItems();
		cbHasta.removeAllItems();
		cbDesde.removeAllItems();
		for (Position<Character> pos : arbol.positions()) {
			cbPadres.addItem(pos.element());
			cbHasta.addItem(pos.element());
			cbDesde.addItem(pos.element());
		}
	}

	/**
	 * Dibuja la pila en una region determinada
	 * 
	 * @param e
	 *            Region donde se dibujara
	 */
	public void graficarPila(Graphics2D e) {
		e.drawImage(background2, 0, 0, null);
		if (pila_a_pintar != null) {
			try {
				pila_temp = new Pila<Character>();
				int dist_nodos = 56;
				int i = 0; // indice de nodo actual para el for
				int margen_derecho = 20, margen_superior = 20;

				while (!pila_a_pintar.isEmpty()) {
					Character rotulo = pila_a_pintar.pop();
					pila_temp.push(rotulo);
					Point2D loc = new Point2D.Double(margen_derecho,
							margen_superior + dist_nodos * i);
					i++;
					e.drawImage(gray, (int) loc.getX(), (int) loc.getY(), null);

					e.setFont(new Font(e.getFont().toString(), Font.BOLD, 14));

					e.setColor(Color.black);

					e.drawString(rotulo.toString(), (int) (loc.getX()
							+ nodoSize.getWidth() / 2 - 5), (int) (loc.getY()
							+ nodoSize.getHeight() / 2 + 5));
				}
				if (i * dist_nodos + margen_derecho > getHeight()) {
					setSize(getWidth(), i * dist_nodos + margen_superior);
				}

				while (!pila_temp.isEmpty()) {
					pila_a_pintar.push(pila_temp.pop());
				}
			} catch (EmptyStackException e1) {
				System.out.println("Esta excepcion no deberia dispararse");
			}
		}

	}

	/**
	 * Dibuja el recorrido del arbol en preorden o posorden segun corresponda
	 * 
	 * @param e
	 *            Region donde se dibujara
	 */
	public void graficarRecorrido(Graphics2D e) {
		e.drawImage(background2, 0, 0, null);
		if (arbol != null && !arbol.isEmpty()) {
			PositionList<Position<Character>> lista;
			if (radioPre.isSelected()) {
				lista = (PositionList<Position<Character>>) arbol
						.preOrderPositions();
			} else {
				lista = (PositionList<Position<Character>>) arbol
						.posOrderPositions();
			}

			// distancia entre los dibujos de los nodos para que entren las
			// flechas
			int dist_nodos = 96;
			int i = 0; // indice de nodo actual para el for
			int margen_derecho = 20, margen_superior = 17;
			for (Position<Character> pos : lista) {
				Point2D loc = new Point2D.Double(margen_derecho + dist_nodos
						* i, margen_superior);
				i++;
				// crear variables para reducir calculos
				e.drawImage(green, (int) loc.getX(), (int) loc.getY(), null);
				if (i != lista.size()) {
					e.drawImage(flecha, (int) loc.getX()
							+ (int) nodoSize.getWidth() + 12,
							(int) loc.getY() + 12, null);
				}
				e.setFont(new Font(e.getFont().toString(), Font.BOLD, 14));
				e.setColor(Color.white);
				e.drawString(pos.element().toString(), (int) (loc.getX()
						+ nodoSize.getWidth() / 2 - 5), (int) (loc.getY()
						+ nodoSize.getHeight() / 2 + 5));
			}
			if (i * dist_nodos + margen_derecho > mpdRecorrido.getWidth()) {
				mpdRecorrido.setPreferredSize(new Dimension(i * dist_nodos
						+ margen_derecho, mpdRecorrido.getHeight()));
				mpdRecorrido.updateUI();
				mpdRecorrido.validate();

			}
		}
	}

	/**
	 * Dibuja la vista tradicional del arbol
	 * 
	 * @param e
	 *            Region donde se dibujara
	 */
	public void graficarArbol(Graphics2D e) {
		e.drawImage(background2, 0, 0, null);
		if (arbol != null) {
			try {
				Line2D arco;
				// Se dibujan los arcos y luego se superponen los circulos
				Point2D centropadre;
				Point2D centro;
				TNode<Character> nodo, padre;
				for (Position<Character> pos : arbol.positions()) {
					nodo = (TNode<Character>) pos;
					padre = nodo.getParent();
					if (!arbol.isRoot(pos)) {
						arco = new Line2D.Double();
						centro = new Point2D.Double(nodo.getCorner().getX()
								+ nodoSize.getWidth() / 2, nodo.getCorner()
								.getY()
								+ nodoSize.getHeight() / 2);
						centropadre = new Point2D.Double(padre.getCorner()
								.getX()
								+ nodoSize.getWidth() / 2, padre.getCorner()
								.getY()
								+ nodoSize.getHeight() / 2);
						e.setColor(Color.blue);
						e.setStroke(new BasicStroke(5));
						arco.setLine(centro, centropadre);
						e.draw(arco);
					}
				}
				for (Position<Character> pos : arbol.positions()) {
					nodo = (TNode<Character>) pos;
					e.drawImage(green, (int) nodo.getCorner().getX(),
							(int) nodo.getCorner().getY(), null);
					e.setFont(new Font(e.getFont().toString(), Font.BOLD, 14));
					e.setColor(Color.white);
					e.drawString(nodo.element().toString(), (int) (nodo
							.getCorner().getX()
							+ nodoSize.getWidth() / 2 - 5), (int) (nodo
							.getCorner().getY()
							+ nodoSize.getHeight() / 2 + 5));
				}

			} catch (InvalidPositionException e1) {
				System.out.println("Esta excepcion no deberia dispararse");
			}
			if (chkCamino.isSelected()) {
				resaltarCamino(e);
			}
			if (chkAncestro.isSelected()) {
				resaltarAncestro(e);
			}
		}
	}

	/**
	 * Resalta el camino de un nodo a otro a partir de los comboboxes "desde" y
	 * "hasta"
	 * 
	 * @param e
	 *            Region donde se dibujara
	 */
	private void resaltarCamino(Graphics2D e) {
		Lista<Character> lista;
		try {
			lista = TestingApplication.route((Character) cbDesde
					.getSelectedItem(), (Character) cbHasta.getSelectedItem());
			Line2D arco;
			Point2D centropadre;
			Point2D centro;
			Position<Character> pos = lista.first();
			boolean salir = false;
			while (!salir) {
				boolean last = pos == lista.last();
				TNode<Character> nodo = (TNode<Character>) arbol.findNodo(pos
						.element());
				if (!last) {
					TNode<Character> siguiente = (TNode<Character>) arbol
							.findNodo(lista.next(pos).element());
					arco = new Line2D.Double();
					centro = new Point2D.Double(nodo.getCorner().getX()
							+ nodoSize.getWidth() / 2, nodo.getCorner().getY()
							+ nodoSize.getHeight() / 2);
					centropadre = new Point2D.Double(siguiente.getCorner()
							.getX()
							+ nodoSize.getWidth() / 2, siguiente.getCorner()
							.getY()
							+ nodoSize.getHeight() / 2);
					e.setColor(Color.red);
					e.setStroke(new BasicStroke(5));
					arco.setLine(centro, centropadre);
					e.draw(arco);
				}
				e.setColor(Color.white);
				e.drawImage(blue, (int) nodo.getCorner().getX(), (int) nodo
						.getCorner().getY(), null);
				e.drawString(nodo.element().toString(), (int) (nodo.getCorner()
						.getX()
						+ nodoSize.getWidth() / 2 - 5), (int) (nodo.getCorner()
						.getY()
						+ nodoSize.getHeight() / 2 + 5));
				if (!last) {
					pos = lista.next(pos);
				} else {
					salir = true;
				}
			}
		} catch (InvalidPositionException e1) {
			System.out.println("Esta excepcion no deberia dispararse");
		} catch (EmptyTreeException e1) {
			System.out.println("Esta excepcion no deberia dispararse");
		} catch (EmptyListException e1) {
			System.out.println("Esta excepcion no deberia dispararse");
		} catch (BoundaryViolationException e1) {
			System.out.println("Esta excepcion no deberia dispararse");
		}
	}

	/**
	 * Resalta el nodo que es ancestro comun de los seleccionados en los
	 * comboboxes "desde" y "hasta"
	 * 
	 * @param e
	 *            Region donde se dibujara
	 */
	private void resaltarAncestro(Graphics2D e) {
		TNode<Character> nodo;
		try {
			nodo = (TNode<Character>) arbol.findNodo(TestingApplication
					.ancestroComun((Character) cbDesde.getSelectedItem(),
							(Character) cbHasta.getSelectedItem()));

			e.setColor(Color.white);
			e.drawImage(orange, (int) nodo.getCorner().getX(), (int) nodo
					.getCorner().getY(), null);
			e.drawString(nodo.element().toString(), (int) (nodo.getCorner()
					.getX()
					+ nodoSize.getWidth() / 2 - 5), (int) (nodo.getCorner()
					.getY()
					+ nodoSize.getHeight() / 2 + 5));
		} catch (EmptyTreeException e1) {
			System.out.println("Esta excepcion no deberia dispararse");
		}

	}

	/**
	 * Dibuja el arbol por niveles
	 * 
	 * @param e
	 *            Region donde se dibujara
	 */
	public void graficarNiveles(Graphics2D e) {
		e.drawImage(background2, 0, 0, null);
		if (arbol != null) {
			int nivel = 0;
			int renglon = 56, margentxt = 20;
			int index = 0;
			int anchotxt = 100;
			e.setFont(new Font(e.getFont().toString(), Font.BOLD, 20));
			for (Position<Character> pos : arbol.listadoNiveles().positions()) {
				if (nivel == 0) {
					e.setColor(Color.white);
					e
							.drawImage(green, margentxt + anchotxt,
									renglon - 32, null);
					e.drawString("Nivel 0:", margentxt, renglon);
					e.setColor(Color.white);
					e.drawString(pos.element().toString(), margentxt + anchotxt
							+ 16, renglon);
					nivel++;
				} else if (pos.element() == null) {
					Point2D txtLoc = new Point2D.Double(20, renglon
							* (nivel + 1));
					e.setColor(Color.white);
					e.drawString("Nivel " + nivel + ":", (int) txtLoc.getX(),
							(int) txtLoc.getY());
					nivel++;
					index = 0;
				} else {
					int locX = anchotxt + margentxt + index * 56, locY = renglon
							* nivel;
					e.drawImage(green, locX, locY - 32, null);
					e.setColor(Color.white);
					e.drawString(pos.element().toString(), locX + 16, locY);
					index++;
				}
			}
		}

	}

	// Variables declaration - do not modify//GEN-BEGIN:variables
	private javax.swing.JButton btnAddNode;
	private javax.swing.JButton btnDeleteLevel;
	private javax.swing.JButton btnEliminarArbol;
	private javax.swing.JButton btnLoadTree;
	private javax.swing.JComboBox cbDesde;
	private javax.swing.JComboBox cbHasta;
	private javax.swing.JComboBox cbNiveles;
	private javax.swing.JComboBox cbPadres;
	private javax.swing.JCheckBox chkAltura;
	private javax.swing.JCheckBox chkAncestro;
	private javax.swing.JCheckBox chkCamino;
	private javax.swing.JPopupMenu clickDerecho;
	private javax.swing.JMenuItem ctxAddSon;
	private javax.swing.JMenuItem ctxDeleteNode;
	private javax.swing.JLabel lblDesde;
	private javax.swing.JLabel lblHasta;
	private javax.swing.JLabel lblNivel;
	private javax.swing.JLabel lblPadre;
	private javax.swing.JLabel lblRotulo;
	private javax.swing.JPanel mpdArbol;
	private javax.swing.JPanel mpdRecorrido;
	private javax.swing.JPanel panelAdd;
	private javax.swing.JPanel panelAncCam;
	private javax.swing.JPanel panelArbol;
	private javax.swing.JPanel panelDeFondo;
	private javax.swing.JPanel panelEliminar;
	private javax.swing.JPanel panelGraficos;
	private javax.swing.JPanel panelMostrarAC;
	private javax.swing.JPanel panelOperaciones;
	private javax.swing.JPanel panelRecorridos;
	private javax.swing.JPanel panelTipoRecorrido;
	private javax.swing.JRadioButton radioArbol;
	private javax.swing.JRadioButton radioNiveles;
	private javax.swing.JRadioButton radioPos;
	private javax.swing.JRadioButton radioPre;
	private javax.swing.JScrollPane scrollArbol;
	private javax.swing.JScrollPane scrollRecorrido;
	private javax.swing.JTextField txtRotulo;
	// End of variables declaration//GEN-END:variables
	private static Image green, orange, blue, gray, red, flecha, background,
			background2;
	private Pila<Character> pila_temp;
	private Pila<Character> pila_a_pintar; // pilas para no perder la que se
	// grafica
	private static Arbol<Character> arbol; // representara el arbol estatico de
	// TestingApplication
	private Point2D last_draw; // almacena la esquina superior izquierda del
	// ultimo nodo que se dibujo para no dibujarlo
	// cada vez q se mueve el puntero sobre el
	private Character last_char; // allmacena el caracter del ultimo nodo
	// dibujado
	private Point2D mousePoint;// almacena la posicion del puntero
	private int niveles;// indica la cantidad de niveles del arbol
	private Dimension nodoSize; // dimension de los nodos
}
